package com.yf.dxapp.module.app.service.login;

import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.module.member.controller.app.auth.vo.AppAuthLoginRespVO;
import cn.iocoder.yudao.module.member.convert.auth.AuthConvert;
import cn.iocoder.yudao.module.system.api.logger.LoginLogApi;
import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi;
import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCreateReqDTO;
import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenRespDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2AccessTokenMapper;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import com.yf.dxapp.module.app.controller.admin.appuser.vo.AppUserPageReqVO;
import com.yf.dxapp.module.app.controller.app.vo.CodeLoginDTO;
import com.yf.dxapp.module.app.controller.app.vo.CodeLoginVO;
import com.yf.dxapp.module.app.controller.app.vo.PhoneLoginDTO;
import com.yf.dxapp.module.app.controller.app.vo.PhoneLoginVO;
import com.yf.dxapp.module.app.dal.dataobject.appuser.AppUserDO;
import com.yf.dxapp.module.app.dal.dataobject.token.TokenDO;
import com.yf.dxapp.module.app.service.appuser.AppUserService;
import com.yf.dxapp.module.app.service.token.TokenService;
import com.yf.dxapp.module.app.sms.SmsService;
import com.yf.dxapp.module.app.util.StringUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;

@Service
@Slf4j
public class LoginServiceImpl implements LoginService {

    @Resource
    private AppUserService appUserService;

    @Resource
    private TokenService tokenService;

    @Resource
    private OAuth2TokenApi oauth2TokenApi;

    @Resource
    private LoginLogApi loginLogApi;

    @Resource
    private SmsService smsService;

    @Override
    public PhoneLoginVO phoneLogin(PhoneLoginDTO phoneLoginDTO) {
        if (!StringUtil.isPhone(phoneLoginDTO.getPhone())) {
            throw exception(new ErrorCode(-1, "手机号有误"));
        }
        if (phoneLoginDTO.getPlatform() == null) {
            throw exception(new ErrorCode(-1, "登录平台信息必传"));
        }
        SmsCodeUseReqDTO smsCodeUseReqDTO = new SmsCodeUseReqDTO();
        smsCodeUseReqDTO.setMobile(phoneLoginDTO.getPhone());
        smsCodeUseReqDTO.setCode(phoneLoginDTO.getCaptcha());
        smsCodeUseReqDTO.setScene(SmsSceneEnum.MEMBER_LOGIN.getScene());
        smsCodeUseReqDTO.setUsedIp(phoneLoginDTO.getUsedIp());
        smsService.verifyCaptcha(phoneLoginDTO.getPhone(), phoneLoginDTO.getCaptcha());
        AppUserPageReqVO req = new AppUserPageReqVO();
        req.setMobile(phoneLoginDTO.getPhone());
        PageResult<AppUserDO> result = appUserService.getAppUserPage(req);
        List<AppUserDO> list = result.getList();
        AppUserDO user;
        if (list.isEmpty()) {
            //是注册
            user = appUserService.phoneRegister(phoneLoginDTO.getTopCode(), phoneLoginDTO.getPhone());
        } else {
            user = list.get(0);
        }
        updateWxId(user, phoneLoginDTO.getCode(), phoneLoginDTO.getUnionId(), phoneLoginDTO.getOpenId());
        AppAuthLoginRespVO appAuthLoginRespVO = createTokenAfterLoginSuccess(user, smsCodeUseReqDTO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE, null);
        TokenDO tokenEntity = tokenService.createToken(user.getId(), phoneLoginDTO.getPlatform(), appAuthLoginRespVO.getAccessToken());
        return new PhoneLoginVO(tokenEntity);
    }

    @Override
    public CodeLoginVO codeLogin(CodeLoginDTO codeLoginDTO) {
        if (!StringUtil.isPhone(codeLoginDTO.getPhone())) {
            throw exception(new ErrorCode(-1, "手机号有误"));
        }
        if (codeLoginDTO.getPlatform() == null) {
            throw exception(new ErrorCode(-1, "登录平台信息必传"));
        }
        AppUserPageReqVO req = new AppUserPageReqVO();
        req.setMobile(codeLoginDTO.getPhone());
        PageResult<AppUserDO> result = appUserService.getAppUserPage(req);
        List<AppUserDO> list = result.getList();
        if (list.isEmpty()) {
            throw exception(new ErrorCode(-1, "用户不存在"));
        }
        AppUserDO user = list.get(0);
        if(!Objects.equals(codeLoginDTO.getPassword(),user.getPassword())){
            throw exception(new ErrorCode(-1, "密码错误"));
        }
        updateWxId(user, codeLoginDTO.getCode(), codeLoginDTO.getUnionId(), codeLoginDTO.getOpenId());
        AppAuthLoginRespVO appAuthLoginRespVO = createTokenAfterLoginSuccess(user, req.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE, null);
        TokenDO tokenEntity = tokenService.createToken(user.getId(), codeLoginDTO.getPlatform(), appAuthLoginRespVO.getAccessToken());
        return new CodeLoginVO(tokenEntity);
    }


    private void updateWxId(AppUserDO user, String code, String unionId, String openId) {
        //openId不存在 code换取
//        if (StringUtil.isBlank(openId) && !StringUtil.isBlank(code)) {
//            try {
//                WxMaJscode2SessionResult result = wxMaService.jsCode2SessionInfo(code);
//                unionId = result.getUnionid();
//                openId = result.getOpenid();
//            } catch (WxErrorException e) {
//                log.error("小程序jsCode2Session失败", e);
//            }
//        }
//        if (!StringUtil.isBlank(unionId)) {
//            user.setUnionId(unionId);
//        }
//        if (!StringUtil.isBlank(openId)) {
//            user.setMiniOpenId(openId);
//        }
//
//        AppUserSaveReqVO updateVo = new AppUserSaveReqVO();
//        appUserService.updateAppUser(updateVo);
    }


    @Override
    public boolean logout(Long userId) {
        if (userId == null) {
            log.info("登出的用户id为空，不处理");
            return false;
        }
        TokenDO token = tokenService.findByUserId(userId);
        if (token == null) {
            log.info("通过userId[{}]查询不到对应的token，暂不出来", userId);
            return false;
        }
        tokenService.deleteoken(token.getId());
        return true;
    }

    @Resource
    private OAuth2AccessTokenMapper oAuth2AccessTokenMapper;

    private AppAuthLoginRespVO createTokenAfterLoginSuccess(AppUserDO user, String mobile,
                                                            LoginLogTypeEnum logType, String openid) {
        // 插入登陆日志
        createLoginLog(user.getId(), mobile, logType, LoginResultEnum.SUCCESS);
        // 创建 Token 令牌
        OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.createAccessToken(new OAuth2AccessTokenCreateReqDTO()
                .setUserId(user.getId()).setUserType(getUserType().getValue())
                .setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT));
        //单点登录 删除别的token
        List<OAuth2AccessTokenDO> tokens = oAuth2AccessTokenMapper.selectList(OAuth2AccessTokenDO::getUserId,user.getId(),OAuth2AccessTokenDO::getUserType,getUserType().getValue());
        for (OAuth2AccessTokenDO tt:
                tokens) {
            if(!tt.getAccessToken().equals(accessTokenRespDTO.getAccessToken())){
                oauth2TokenApi.removeAccessToken(tt.getAccessToken());
            }

        }
        // 构建返回结果
        return AuthConvert.INSTANCE.convert(accessTokenRespDTO, openid);
    }

    private void createLoginLog(Long userId, String mobile, LoginLogTypeEnum logType, LoginResultEnum loginResult) {
        // 插入登录日志
        LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO();
        reqDTO.setLogType(logType.getType());
        reqDTO.setTraceId(TracerUtils.getTraceId());
        reqDTO.setUserId(userId);
        reqDTO.setUserType(getUserType().getValue());
        reqDTO.setUsername(mobile);
        reqDTO.setUserAgent(ServletUtils.getUserAgent());
        reqDTO.setUserIp(getClientIP());
        reqDTO.setResult(loginResult.getResult());
        loginLogApi.createLoginLog(reqDTO);
        // 更新最后登录时间
//        if (userId != null && Objects.equals(LoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) {
//            userService.updateUserLogin(userId, getClientIP());
//        }
    }

    private UserTypeEnum getUserType() {
        return UserTypeEnum.MEMBER;
    }
}
